<template>
  <div class="whiteboard">
    <div class="inner draw" @mousemove="beginPath($event)">
      <div class="wrap">
        <canvas
          id="canvas"
          class="fl"
          width="600"
          height="400"
          @mousedown="canvasDown($event)"
          @mouseup="canvasUp($event)"
          @mousemove="canvasMove($event)"
        >
        </canvas>
        <div id="control" class="fl">
          <!--画笔颜色-->
          <div id="canvas-color">
            <h5>画笔颜色</h5>
            <ul>
              <li
                v-for="item in colors"
                :class="{ active: config.lineColor === item }"
                :style="{ background: item }"
                @click="setColor(item)"
              ></li>
            </ul>
          </div>
          <!--画笔-->
          <div id="canvas-brush">
            <h5>画笔大小</h5>
            <span
              v-for="pen in brushs"
              :class="[
                pen.className,
                { active: config.lineWidth === pen.lineWidth },
              ]"
              @click="setBrush(pen.lineWidth)"
            ></span>
          </div>
          <!--操作-->
          <div id="canvas-control">
            <h5>操作</h5>
            <span
              v-for="control in controls"
              :title="control.title"
              :class="control.className"
              @click="controlCanvas(control.action)"
            ></span>
          </div>
          <!-- 生成图像-->
          <div id="canvas-drawImage">
            <h5>生成图像</h5>
            <button class="drawImage" @click="getImage()">预览</button>
          </div>
        </div>
      </div>
      <!--存放图片-->
      <div id="img-box" v-show="imgUrl.length">
        <div class="img-item" v-for="src in imgUrl">
          <img :src="src" />
          <span class="fa fa-close" @click="removeImg(src)"></span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, PropType, reactive, ref, watch } from "vue";
import { useRouter } from "vue-router";

const router = useRouter();

const props = defineProps({
  isShow: {
    type: Boolean,
    default: false,
  },
  whiteboardData: {
    type: Object as PropType<IImage>,
    required: true,
  },
});

const colors = ["#fef4ac", "#0018ba", "#ffc200", "#f32f15", "#ccc", "#5ab639"];
const brushs = [
  {
    className: "small fa fa-paint-brush",
    lineWidth: 3,
  },
  {
    className: "middle fa fa-paint-brush",
    lineWidth: 6,
  },
  {
    className: "big fa fa-paint-brush",
    lineWidth: 12,
  },
];
const context = ref();
const imgUrl = ref<string[]>([]);
const canvasMoveUse = ref(false);
const preDrawAry = ref<any>([]);
const nextDrawAry = ref<any>([]);
const middleAry = ref<any>([]);
const config = reactive({
  lineWidth: 1,
  lineColor: "#f2849e",
  shadowBlur: 2,
});

const emit = defineEmits(["getMessage"]);

const ws = ref();
const userData = ref<IUserData>({
  roomId: "",
  sex: "boy",
  username: "",
});

const controls = computed(() => {
  return [
    {
      title: "上一步",
      action: "prev",
      className: preDrawAry.value.length ? "active fa fa-reply" : "fa fa-reply",
    },
    {
      title: "下一步",
      action: "next",
      className: nextDrawAry.value.length
        ? "active fa fa-share"
        : "fa fa-share",
    },
    {
      title: "清除",
      action: "clear",
      className:
        preDrawAry.value.length || nextDrawAry.value.length
          ? "active fa fa-trash"
          : "fa fa-trash",
    },
  ];
});

const removeImg = (src: string) => {
  imgUrl.value = imgUrl.value.filter((item) => item !== src);
};

const initDraw = () => {
  const preData = context.value.getImageData(0, 0, 600, 400);
  // 空绘图表面进栈
  middleAry.value.push(preData);
};

const canvasMove = (e: any) => {
  if (canvasMoveUse.value) {
    console.log("canvasMove");
    const t = e.target;
    let canvasX = e.clientX - t.parentNode.offsetLeft;
    let canvasY = e.clientY - t.parentNode.offsetTop;
    context.value.lineTo(canvasX, canvasY);
    context.value.stroke();
  }
};

const beginPath = (e: any) => {
  const canvas = document.querySelector("#canvas");
  if (e.target !== canvas) {
    console.log("beginPath");
    context.value.beginPath();
  }
};

const canvasUp = (e: any) => {
  console.log("canvasUp");
  const preData = context.value.getImageData(0, 0, 600, 400);
  if (!nextDrawAry.value.length) {
    middleAry.value.push(preData);
  } else {
    middleAry.value = [];
    middleAry.value = middleAry.value.concat(preDrawAry.value);
    middleAry.value.push(preData);
    nextDrawAry.value = [];
  }
  canvasMoveUse.value = false;
};

const canvasDown = (e: any) => {
  console.log("canvasDown");
  canvasMoveUse.value = true;
  const t = e.target;
  let canvasX = e.clientX - t.parentNode.offsetLeft;
  let canvasY = e.clientY - t.parentNode.offsetTop;
  setCanvasStyle();
  // 清除子路径
  context.value.beginPath();
  context.value.moveTo(canvasX, canvasY);
  console.log("moveTo", canvasX, canvasY);
  // 当前绘图表面状态
  const preData = context.value.getImageData(0, 0, 600, 400);
  // 当前绘图表面进栈
  preDrawAry.value.push(preData);
};

const setColor = (color: string) => {
  config.lineColor = color;
};

const setBrush = (type: number) => {
  config.lineWidth = type;
};

const controlCanvas = (action: string) => {
  switch (action) {
    case "prev":
      if (preDrawAry.value.length) {
        const popData = preDrawAry.value.pop();
        const midData = middleAry.value[preDrawAry.value.length + 1];
        nextDrawAry.value.push(midData);
        context.value.putImageData(popData, 0, 0);
      }
      break;
    case "next":
      if (nextDrawAry.value.length) {
        const popData = nextDrawAry.value.pop();
        const midData =
          middleAry.value[
            middleAry.value.length - nextDrawAry.value.length - 2
          ];
        preDrawAry.value.push(midData);
        context.value.putImageData(popData, 0, 0);
      }
      break;
    case "clear":
      context.value.clearRect(
        0,
        0,
        context.value.canvas.width,
        context.value.canvas.height
      );
      preDrawAry.value = [];
      nextDrawAry.value = [];
      middleAry.value = [middleAry.value[0]];
      break;
  }
};

const getImage = () => {
  const canvas = document.querySelector("#canvas") as HTMLCanvasElement;
  return canvas.toDataURL("image/png", 0.5);
};

const setCanvasStyle = () => {
  context.value.lineWidth = config.lineWidth;
  context.value.shadowBlur = config.shadowBlur;
  context.value.shadowColor = config.lineColor;
  context.value.strokeStyle = config.lineColor;
};

// 建立socket连接时
const openSocket = () => {
  const newMessage: IImage = {
    type: "guest",
    username: userData.value.username,
    roomId: userData.value.roomId,
    image: getImage(),
  };
  // ws.value.send(JSON.stringify(newMessage));
};

// 关闭socket连接时
const closeSocket = () => {
  console.log("连接关闭");
};

// 监听socket错误
const errorSocket = (msg: any) => {
  alert("服务器连接失败");
};

// 监听socket消息
const getMessageSocket = (msg: any) => {
  emit("getMessage", JSON.parse(msg.data));
};

// 发送socket消息
const putMessageSocket = (str: any) => {
  ws.value.send(JSON.stringify(str));
};

const initWebSocket = () => {
  try {
    userData.value = JSON.parse(localStorage.getItem("userData") || "");
    ws.value = new WebSocket(
      `ws://127.0.0.1:8080/whiteboard/${userData.value.roomId}`
    );
    ws.value.onopen = openSocket;
    ws.value.onclose = closeSocket;
    ws.value.onerror = errorSocket;
    ws.value.onmessage = getMessageSocket;
  } catch {
    router.push("/");
  }
};

watch(props, () => {
  if (props.isShow && props.whiteboardData.type !== "host") {
    const newMessage: IImage = {
      type: "host",
      username: userData.value.username,
      roomId: userData.value.roomId,
      image: "",
    };
    putMessageSocket(newMessage);
  }
});

// 查看字符串存储大小
function getSessionStorageSize(str: string) {
  let size = JSON.stringify(str).length * 2;
  const arr = ["bytes", "KB", "MB", "GB", "TB"];
  let sizeUnit = 0;

  while (size > 1024) {
    size /= 1024;
    ++sizeUnit;
  }

  return `大小为：${size.toFixed(2)}${arr[sizeUnit]}`;
}

watch(
  () => [preDrawAry, middleAry],
  () => {
    if (ws.value && ws.value.readyState === 1) {
      const newMessage: IImage = {
        type: "host",
        username: userData.value.username,
        roomId: userData.value.roomId,
        image: getImage(),
      };
      putMessageSocket(newMessage);
    }
  },
  { deep: true }
);

const closeWhiteboard = () => {
  if (props.whiteboardData.username !== userData.value.username) return;
  const newMessage: IImage = {
    type: "close",
    username: userData.value.username,
    roomId: userData.value.roomId,
    image: "",
  };
  putMessageSocket(newMessage);
};

const init = () => {
  const canvas = document.querySelector("#canvas") as HTMLCanvasElement;
  context.value = canvas.getContext("2d");
  initDraw();
  setCanvasStyle();
  document.querySelector("#footer")?.classList.add("hide-footer");
  document.querySelector("body")?.classList.add("fix-body");
  initWebSocket();
};

onMounted(() => init());

defineExpose({ closeWhiteboard });
</script>

<style lang="scss" scoped>
.whiteboard {
  display: flex;
}
@media screen and (max-width: 700px) {
  #img-box,
  #canvas-drawImage h5,
  #canvas-brush {
    display: none;
  }
  #canvas-drawImage button {
    width: auto;
    position: absolute;
    flex: 1;
  }
  .wrap #control {
    width: 100%;
    height: auto;
    display: flex;
    flex-direction: row;
    text-align: center;
  }
}
.fix-body {
  position: fixed !important;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  overflow: hidden;
}
.inner.draw {
  display: flex;
  flex-direction: row;
}
.draw h5 {
  margin-bottom: 10px;
}
#img-box {
  flex: 1;
  padding-left: 10px;
}
#img-box .img-item {
  position: relative;
  display: inline-block;
}
#img-box .img-item .fa {
  position: absolute;
  cursor: pointer;
  right: 1px;
  top: -1px;
  font-size: 12px;
  font-weight: 1;
  display: none;
  color: #ccc;
}
#img-box .img-item:hover .fa {
  display: block;
}
#img-box .img-item .fa:hover {
  color: #f2849e;
}
#img-box img {
  border: 1px #ccc solid;
  width: 90px;
  height: 60px;
  margin: 5px;
}
.wrap {
  width: 740px;
  border: 1px #585858 solid;
  overflow: hidden;
}
.fl {
  float: left;
  display: block;
}
#canvas {
  border-right: 1px #585858 solid;
  cursor: crosshair;
}
#control {
  width: 130px;
  height: 400px;
  margin-left: 4px;
}
#control div {
  padding: 5px;
}
#canvas-color ul {
  overflow: hidden;
  margin: 0;
  padding: 0;
}
#canvas-color ul li {
  float: left;
  display: inherit;
  width: 13px;
  height: 13px;
  border: 3px #fff solid;
  margin: 8px;
  cursor: pointer;
}
#canvas-color .active {
  border: 1px solid #f2849e;
}
#canvas-brush span {
  display: inline-block;
  width: 20px;
  height: 15px;
  margin-left: 10px;
  cursor: pointer;
}
#canvas-brush .small {
  font-size: 12px;
}
#canvas-brush .middle {
  font-size: 14px;
}
#canvas-brush .big {
  font-size: 16px;
}

#canvas-control span {
  display: inline-block;
  font-size: 14px;
  width: 20px;
  height: 15px;
  margin-left: 10px;
  cursor: pointer;
}
#canvas-control .active,
#canvas-brush .active {
  color: #f2849e;
}
.drawImage {
  width: 100px;
  height: 30px;
  font-size: 12px;
  line-height: 30px;
}
</style>
